﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genuilder.Extensibility
{
	public abstract class CodeRepositoryBase : ICodeRepository, DependencyNodeRepository
	{
		TaskQueue tasks = new TaskQueue();
		bool _Initialized;
		public void Initialize()
		{
			if(_Initialized)
				throw new InvalidOperationException("Already initialized");
			_Initialized = true;
			foreach(var root in RootSourceItemNames)
			{
				var rootLocal = root;
				tasks.Enqueue(() =>
				{
					var item = Get(rootLocal);
					var transition = GetTransition(item);
					transition.PlayChange(item);
				});
			}


			tasks.Run();

			foreach(var generatedSource in GeneratedSourceItemNames)
			{
				var localGeneratedSource = generatedSource;
				tasks.Enqueue(() =>
				{
					var wasTracked = _CurrentItems.ContainsKey(localGeneratedSource);
					var item = Get(localGeneratedSource);
					var transition = GetTransition(item);
					if(wasTracked && transition.NewState == CodeItemState.Excluded)
					{
						transition.NewState = CodeItemState.Exist;
						transition.Modified = true;
					}
					transition.PlayChange(item);
				});
			}

			tasks.Run();
			OnInitialized(_CurrentItems.Values.ToList());
		}

		public abstract CodeItemHistory GetTransition(CodeItem item);

		public abstract IEnumerable<string> RootSourceItemNames
		{
			get;
		}

		public abstract IEnumerable<string> GeneratedSourceItemNames
		{
			get;
		}

		protected abstract IEnumerable<CodeItemHistory> GetCodeItemHistories();

		//protected abstract CodeItemHistory GetHistory(CodeItem item);

		protected virtual void OnInitialized(IEnumerable<CodeItem> trackedItems)
		{
		}



		private void OnCodeItemCreated(CodeItem item)
		{
			tasks.Enqueue(() =>
			{
				item._IsCreating = true;
				try
				{

					if(CodeItemCreated != null)
						CodeItemCreated(this, item);

				}
				finally
				{
					item._IsCreating = false;
				}
			});
		}

		Dictionary<String, CodeItem> _CurrentItems = new Dictionary<string, CodeItem>();

		#region ICodeRepository Members

		public CodeItem Get(string name)
		{
			CodeItem item = GetFromRepository(name);
			if(item == null)
			{
				item = CreateCodeItem(name, CodeItemState.Exist);
				item.TaskQueue = tasks;
				AddToRepository(item);
				OnCodeItemCreated(item);
			}
			return item;
		}

		protected void AddToRepository(CodeItem item)
		{
			_CurrentItems.Add(item.Name, item);
		}

		protected CodeItem GetFromRepository(string name)
		{
			CodeItem item;
			if(_CurrentItems.TryGetValue(name, out item))
			{
				return item;
			}
			return null;
		}

		protected abstract CodeItem CreateCodeItem(string name, CodeItemState state);
		//protected abstract IEnumerable<CodeItemHistory> GetCodeItemHistories();

		public event CodeItemCreatedHandler CodeItemCreated;


		#endregion

		Dictionary<String, DependencyNode> _DependencyNodes = new Dictionary<string, DependencyNode>();

		#region DependencyNodeRepository Members

		public DependencyNode Get(CodeItem item)
		{
			DependencyNode node;
			if(_DependencyNodes.TryGetValue(item.Name, out node))
			{
				return node;
			}
			node = new DependencyNode(item, this, tasks, RootSourceItemNames.Contains(item.Name));
			_DependencyNodes.Add(item.Name, node);
			return node;
		}

		#endregion

		protected void ConfigureCodeItem(CodeItem item)
		{
			item.Repository = this;
			item.TaskQueue = tasks;
		}
	}


	public class CodeItemHistory
	{
		public CodeItemHistory(string itemName)
		{
			_ItemName = itemName;
		}
		private readonly string _ItemName;
		public string ItemName
		{
			get
			{
				return _ItemName;
			}
		}

		public bool Modified
		{
			get;
			set;
		}

		public CodeItemState NewState
		{
			get;
			set;
		}

		public virtual void PlayChange(CodeItem item)
		{
			if(item.State != NewState)
				item.ChangeState(NewState);
			if(Modified)
				item.OnContentChanged();
		}

	}
}
